﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using blackhouse.BlackApart.Business.Reservations;
using blackhouse.BlackApart.Business;

namespace blackhouse.BlackApart.Web {
    public class SearchReservationPerRequest {

        #region Fields

        private List<SearchVariant> variants = new List<SearchVariant>();
        private Dictionary<Variant, SearchVariant> relation = new Dictionary<Variant, SearchVariant>();
        private Dictionary<int, Variant> relation2 = new Dictionary<int, Variant>();

        private Factory factory = Factory.Instance();

        #endregion

        #region Properties

        public DateTime ArrivalDate { get; private set; }

        public DateTime DepartureDate { get; private set; }

        public int NumberOfPeople { get; private set; }

        public SearchVariant[] Variants {
            get {
                return this.variants.ToArray();
            }
            set {
                this.variants = new List<SearchVariant>(value);
            }
        }

        public string Id { get; set; }

        #endregion

        #region Constuctors

        public SearchReservationPerRequest(DateTime setArrivalDate, DateTime setDepartureDate, int setNumberOfPeople) {
            this.ArrivalDate = setArrivalDate;
            this.DepartureDate = setDepartureDate;
            this.NumberOfPeople = setNumberOfPeople;
            this.Variants = new SearchVariant[0];
        }

        public SearchReservationPerRequest(string reservationId, DirectoryInfo saveDirectory) {
            this.Read(reservationId, saveDirectory);
        }

        #endregion

        #region Methods

        public void AddVariant(Variant variant) {
            SearchVariant searchVariant = this.Convert(variant);
            this.variants.Add(searchVariant);
            this.relation.Add(variant, searchVariant);
            this.relation2.Add(searchVariant.Id, variant);
        }

        public int GetIdForVariant(Variant variant) {
            if (relation.ContainsKey(variant))
                return relation[variant].Id;
            else return 0;
        }

        public Variant GetVariantFromId(int id) {
            if (relation2.ContainsKey(id))
                return this.relation2[id];
            else
                return null;
        }

        private SearchVariant Convert(Variant variant) {
            SearchVariant sv = new SearchVariant();
            sv.Id = Variants.Length + 1;
            foreach (VariantItem item in variant.Items) {
                SearchVariantLine svl = new SearchVariantLine();
                svl.Apartment = item.Apartment.Id;
                svl.ArrivalDate = item.ArrivalDate;
                svl.DepartureDate = item.DepartureDate;
                svl.NumberOfPeople = item.NumberOfPeoples;
                sv.Lines.Add(svl);
            }
            return sv;
        }

        private Variant Convert(SearchVariant variant) {
            Variant v = new Variant();
            foreach (SearchVariantLine line in variant.Lines) {
                v.AddItem(factory.GetApartment(line.Apartment), line.ArrivalDate, line.DepartureDate, line.NumberOfPeople);
            }
            return v;
        }

        private void Read(string reservationId, DirectoryInfo saveDirectory) {
            this.Id = reservationId;
            SearchForReservation sfr = null;
            FileInfo fi = new FileInfo(saveDirectory.FullName + @"\" + this.Id + ".xml");
            if (fi.Exists) {
                using (FileStream fs = fi.OpenRead()) {
                    XmlSerializer serializer = new XmlSerializer(typeof(SearchForReservation));
                    sfr = serializer.Deserialize(fs) as SearchForReservation;
                }
            }
            if (sfr != null) {
                this.MakeMe(sfr);
            }
        }

        private void MakeMe(SearchForReservation sfr) {
            this.ArrivalDate = sfr.SetArrivalDate;
            this.DepartureDate = sfr.SetDepartureDate;
            this.NumberOfPeople = sfr.NumberOfPeople;
            foreach (SearchVariant sv in sfr.Variants) {
                Variant v = this.Convert(sv);
                this.variants.Add(sv);
                this.relation.Add(v, sv);
                this.relation2.Add(sv.Id, v);
            }
        }

        public void Save(DirectoryInfo saveDirectory) {
            this.Id = (DateTime.Now.Ticks - (this.DepartureDate.Ticks - this.ArrivalDate.Ticks) + this.NumberOfPeople + this.Variants.Length).ToString();
            using (FileStream fs = File.Create(saveDirectory.FullName + @"\" + this.Id + ".xml")) {
                XmlWriter writer = XmlWriter.Create(fs);
                SearchForReservation sfr = new SearchForReservation();
                sfr.SetArrivalDate = this.ArrivalDate;
                sfr.SetDepartureDate = this.DepartureDate;
                sfr.NumberOfPeople = this.NumberOfPeople;
                sfr.Variants.AddRange(this.variants);
                XmlSerializer serializer = new XmlSerializer(typeof(SearchForReservation));
                serializer.Serialize(writer, sfr);
            }
        }

        public static void RemoveUnnecessaryFiles(DirectoryInfo directoryInfo, TimeSpan olderThat) {
            foreach (FileInfo fi in directoryInfo.GetFiles().Where(fi => fi.CreationTime + olderThat < DateTime.Now)) {
                try {
                    fi.Delete();
                }
                catch { }
            }
        }

        #endregion

        #region Class

        [Serializable]
        public class SearchForReservation {

            public SearchForReservation() {
                this.Variants = new List<SearchVariant>();
            }

            public DateTime SetArrivalDate { get; set; }
            public DateTime SetDepartureDate { get; set; }
            public int NumberOfPeople { get; set; }
            public List<SearchVariant> Variants { get; set; }
        }


        [Serializable]
        public class SearchVariant {

            public SearchVariant() {
                this.Lines = new List<SearchVariantLine>();
            }

            public int Id { get; set; }
            public List<SearchVariantLine> Lines { get; set; }
        }

        [Serializable]
        public class SearchVariantLine {
            public int Apartment { get; set; }
            public DateTime ArrivalDate { get; set; }
            public DateTime DepartureDate { get; set; }
            public int NumberOfPeople { get; set; }
        }

        #endregion

    }
}